package com.hb.core.exception;

import com.hb.core.base.Result;
import com.hb.core.enums.BaseEnums;
import com.hb.util.Results;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description: 全局异常处理
 * @projectName: zhb-frame-build
 * @author: zhouhaizhi
 * @createTime: 2021/8/25 11:02
 * @version:1.0
 */
@Slf4j
@RestControllerAdvice
public class DefaultExceptionHandler extends AbstractExceptionHandler {

    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity handleConstrainViolationException(ConstraintViolationException e) {
        List<String> msgList = new ArrayList<>();
        for (ConstraintViolation<?> constraintViolation : e.getConstraintViolations()) {
            msgList.add(constraintViolation.getMessage());
        }
        String msg = StringUtils.join(msgList.toArray(), ";");
        log.warn(":::参数校验异常:::{}", msg);
        return this.buildResponseEntity(e, msg);
    }

    @ExceptionHandler(value = {BindException.class, MethodArgumentNotValidException.class})
    public ResponseEntity handleBindException(Exception e) {
        BindingResult bindingResult = null;
        if (e instanceof BindException) {
            BindException bindException = (BindException) e;
            bindingResult = bindException.getBindingResult();
        } else if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException) e;
            bindingResult = methodArgumentNotValidException.getBindingResult();
        }
        List<ObjectError> objectErrors = bindingResult.getAllErrors();
        String msg = objectErrors.stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(";"));
        String code = objectErrors.stream().map(ObjectError::getCode).collect(Collectors.joining(";"));
        log.warn(":::参数校验异常:::{}", msg);
        return this.buildResponseEntity(e, msg);
    }

    /*
        处理 ServiceException 异常
     */
    @ExceptionHandler(ServiceException.class)
    public ResponseEntity serviceExceptionHandle(ServiceException e) {
        log.warn(":::业务异常:::{}", e.getMessage());
        return this.buildResponseEntity(e, e.getMessage());
    }

    /**
     * 处理 Exception 异常
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity exceptionHandler(Exception e) {
        log.error(":::其它异常:::{}", e.getMessage(), e);
        return this.buildResponseEntity(e);
    }

    /**
     * 处理 NoHandlerFoundException 异常. <br/>
     * 需配置 [spring.mvc.throw-exception-if-no-handler-found=true]
     * 需配置 [spring.resources.add-mappings=false]
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity handleNotFoundException(NoHandlerFoundException e) {
        Result result = Results.failure(BaseEnums.NOT_FOUND.code(), BaseEnums.NOT_FOUND.desc());
        result.setStatus(HttpStatus.SC_NOT_FOUND);
        log.info(":::系统异常:::{}", e.getMessage());
        return this.buildResponseEntity(e, e.getMessage());
    }

    private ResponseEntity buildResponseEntity(Exception e) {
        return buildResponseEntity(e, null);
    }

    private ResponseEntity buildResponseEntity(Exception e, String custErrMsg) {
        if (StringUtils.isBlank(custErrMsg)) {
            return build(e);
        }
        return build(e, custErrMsg);
    }


}
